package morenoapp.components.common;

import java.awt.LayoutManager;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import morenoapp.MorenoApp;
import morenoapp.util.ShouldNotHappenException;
import org.jdesktop.application.ApplicationContext;
import org.jdesktop.application.ResourceMap;
import morenoapp.components.common.meta.MapToAction;
import morenoapp.components.common.meta.TextKey;
import morenoapp.components.common.meta.UseName;
import morenoapp.model.data.MorenoModelFace;
import morenoapp.util.I18N;

/**
 *
 * @author dmitry.mamonov
 */
public abstract class SwingAppPanel extends JPanel {
    private ApplicationContext context = null;
    private ResourceMap resources = null;
    private ActionMap actions = null;
    public SwingAppPanel() {
        super();
        init();
    }

    public SwingAppPanel(boolean isDoubleBuffered) {
        super(isDoubleBuffered);
        init();
    }

    public SwingAppPanel(LayoutManager layout) {
        super(layout);
        init();
    }

    public SwingAppPanel(LayoutManager layout, boolean isDoubleBuffered) {
        super(layout, isDoubleBuffered);
        init();
    }

    private void init() {
        try {
            for (Field field : getClass().getDeclaredFields()) {
                if (JComponent.class.isAssignableFrom(field.getType())) {
                    JComponent component;
                    boolean fieldAccessibleFlag = field.isAccessible();
                    try {
                        field.setAccessible(true);
                        component = (JComponent) field.get(this);
                    } finally {
                        field.setAccessible(fieldAccessibleFlag);
                    }
                    if (component != null) {
                        if (field.getAnnotation(UseName.class) != null) {
                            component.setName(field.getName());
                        }

                        MapToAction mapToAction = field.getAnnotation(MapToAction.class);
                        if (mapToAction != null) {
                            Method methodSetAction = component.getClass().getMethod("setAction", Action.class);
                            methodSetAction.invoke(component, getActions().get(mapToAction.value()));
                        }

                        TextKey textKey = field.getAnnotation(TextKey.class);
                        if (textKey != null) {
                            if (component instanceof JLabel) {
                                JLabel label = (JLabel) component;
                                label.setText(I18N.get(textKey.value()));
                            } else if (component instanceof JButton) {
                                JButton button = (JButton) component;
                                button.setText(I18N.get(textKey.value()));
                            } else {
                                throw new ShouldNotHappenException();
                            }
                        }
                    }
                }
            }
        } catch (IllegalArgumentException ex) {
            throw new ShouldNotHappenException(ex);
        } catch (IllegalAccessException ex) {
            throw new ShouldNotHappenException(ex);
        } catch (NoSuchMethodException ex) {
            throw new ShouldNotHappenException(ex);
        } catch (InvocationTargetException ex) {
            throw new ShouldNotHappenException(ex);
        } catch (SecurityException ex) {
            throw new ShouldNotHappenException(ex);
        }
    }

    public ApplicationContext getContext() {
        if (context == null) {
            context = MorenoApp.getApplication().getContext();
        }
        return context;
    }

    /**
     * Provides cached map of actions for current panel.
     * @return
     */
    public ActionMap getActions() {
        if (actions == null) {
            actions = getContext().getActionMap(this);
        }
        return actions;
    }

    public ResourceMap getResources() {
        if (resources == null) {
            resources = getContext().getResourceMap(this.getClass());
        }
        return resources;
    }

    protected abstract void initComponents();

    protected abstract void initLayout();
}
